package thss.lau.secretshare;

import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.security.SecureRandom;
import java.util.List;
import java.util.Random;

/**
 * 
 * @author Lau My implementation of 'Shamir's Secret Sharing'.
 * 
 */
public class SecretShare {
	private int n;
	private int k;
	private String secret;
	private BigInteger p;
	private BigInteger e;
	private Equation equation;

	public SecretShare(int n, int k, String secret) {
		this.n = n;
		this.k = k;
		this.secret = secret;
		strToBigInt();
		initModulus();
		Random rnd = new SecureRandom();
		BigInteger[] coefficients = new BigInteger[k];
		coefficients[0] = e;
		BigInteger num;
		for (int i = 1; i < coefficients.length; i++) {
			num = BigInteger.valueOf(rnd.nextLong());
			num = num.multiply(BigInteger.valueOf(rnd.nextLong()));
			num = num.abs();
			num = num.mod(p);
			coefficients[i] = num.mod(e); // to do
		}
		equation = new Equation(coefficients);

	}

	private void strToBigInt() {
		try {
			e = new BigInteger(secret.getBytes("UTF-8"));
		} catch (UnsupportedEncodingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			System.err.println("Type cast err.");
		}
	}

	private void initModulus() {
		int secLen = e.bitLength();
		if (secLen < 180) {
			p = new BigInteger(
					"14976407493557531125525728362448106789840013430353915016137");
		} else if (secLen < 370) {
			p = new BigInteger("830856716641269388050926147210"
					+ "378437007763661599988974204336"
					+ "741171904442622602400099072063"
					+ "84693584652377753448639527");
		} else if (secLen < 4024) {
			p = new BigInteger("1671022210261044010706804337146599012127"
					+ "9427984758140486147735732543262527544919"
					+ "3095812289909599609334542417074310282054"
					+ "0780117501097269771621177740562184444713"
					+ "5311624699359973445785442150139493030849"
					+ "1201896951396220211014303634039307573549"
					+ "4951338587994892653929285926514054477984"
					+ "1897745831487644537568464106991023630108"
					+ "6045751504900830441750495932712549251755"
					+ "0884842714308894440025555839788342744866"
					+ "7101368958164663781091806630951947745404"
					+ "9899622319436016030246615841346729868014"
					+ "9869334160881652755341231281231973786191"
					+ "0590928243420749213395009469338508019541"
					+ "0958855418900088036159728065975165578015"
					+ "3079187511387238090409461192977321170936"
					+ "6081401737953645348323163171237010704282"
					+ "8481068031277612787461827099245660019965"
					+ "4423851454616735972464821439378482870833"
					+ "7709298145449348366148476664877596527269"
					+ "1765522730435723049823184958030880339674"
					+ "1433100452606317504985611860713079871716"
					+ "8809146278034477061142090096734446658190"
					+ "8273334857030516871663995504285034522155"
					+ "7158160427604895839673593745279150722839"
					+ "3997083495197879290548002853265127569910"
					+ "9306488129210915495451479419727501586051"
					+ "1232507931203905482587057398637416125459"
					+ "0876872367709717423642369650017374448020"
					+ "8386154750356267714638641781056467325078"
					+ "08534977443900875333446450467047221");
		} else {
			int numbits = secLen + secLen * 6 / 5;
			Random random = new SecureRandom();
			p = BigInteger.probablePrime(numbits, random);
		}
	}

	public Info[] getPieces() {
		Info[] rlt = new Info[n];
		BigInteger val = null;
		for (int i = 1; i < n + 1; i++) {
			val = equation.getValue(BigInteger.valueOf(i)).mod(p);
			rlt[i - 1] = new Info(i, val);
		}
		return rlt;
	}

	public String toString() {
		return this.equation.toString();
	}

	public BigInteger decypt(List<Info> infos) {
		if (infos.size() != k) {
			return null;
		}
		for (Info i : infos) {
			i.setB(infos, p);
		}
		BigInteger k = null;
		for (int i = 0; i < infos.size(); i++) {
			if (i == 0) {
				k = infos.get(i).getVal().multiply(infos.get(i).getB());
			} else {
				k = k.add(infos.get(i).getVal().multiply(infos.get(i).getB()));
			}
		}
		return k.mod(p);
	}

}
